import logging
from django.db.models import Q
from django.utils import timezone
from django.shortcuts import get_object_or_404

from rest_framework import status, viewsets, mixins, filters, permissions
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.decorators import action
from django_filters.rest_framework import DjangoFilterBackend

from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiExample
from drf_spectacular.types import OpenApiTypes

from .models import Notification, NotificationTemplate, WechatSubscription, MessageRecord
from .serializers import (
    NotificationSerializer, NotificationCreateSerializer,
    NotificationTemplateSerializer, WechatSubscriptionSerializer,
    WechatSubscriptionCreateSerializer, MessageRecordSerializer,
    NotificationListSerializer
)
from user_app.models import User

logger = logging.getLogger(__name__)


class IsDriverOrShipper(permissions.BasePermission):
    """
    自定义权限类，只允许经过认证的司机和货主创建通知
    """
    
    def has_permission(self, request, view):
        # 只对create操作进行权限检查
        if view.action == 'create':
            # 检查用户是否已认证
            if not request.user.is_authenticated:
                return False
            
            # 检查用户角色是否为司机或货主，并且已通过认证
            return (
                (request.user.role == User.Role.DRIVER or request.user.role == User.Role.SHIPPER) 
                and request.user.role_authstatus
            )
        
        # 对于其他操作，使用默认权限检查
        return True


class NotificationViewSet(mixins.CreateModelMixin,
                          mixins.RetrieveModelMixin,
                          mixins.ListModelMixin,
                          viewsets.GenericViewSet):
    """通知视图集
    
    提供通知的创建、详情、列表操作，以及标记通知为已读的功能。
    标记已读支持单个和批量操作，通过mark_as_read接口的参数控制：
    - all=true: 标记所有未读通知为已读
    - all=false或不提供: 标记指定ID的通知为已读
    
    通知类型说明：
    * ORDER ('order') - 订单通知
    * PAYMENT ('payment') - 支付通知
    * SYSTEM ('system') - 系统通知
    * MESSAGE ('message') - 消息通知
    """
    
    queryset = Notification.objects.all()
    serializer_class = NotificationSerializer
    permission_classes = [IsAuthenticated]
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    filterset_fields = ['notification_type', 'level', 'is_read']
    ordering_fields = ['created_at']
    ordering = ['-created_at']
    
    def get_permissions(self):
        """根据操作设置权限"""
        if self.action == 'create':
            permission_classes = [IsAuthenticated, IsAdminUser]
        else:
            permission_classes = [IsAuthenticated]
        return [permission() for permission in permission_classes]
    
    def get_serializer_class(self):
        """根据操作选择序列化器"""
        if self.action == 'create':
            return NotificationCreateSerializer
        elif self.action == 'list':
            return NotificationListSerializer
        return self.serializer_class
    
    def get_queryset(self):
        """获取查询集"""
        queryset = super().get_queryset()
        
        # 所有操作都只返回当前用户的通知，确保用户无法访问其他用户的通知
        return queryset.filter(recipient=self.request.user)
    
    @extend_schema(
        summary="获取通知详情",
        description="""
获取指定通知的详细信息。

权限说明：
- 只有通过认证的用户可以访问此接口
- 用户只能获取自己的通知详情
""",
        responses={200: NotificationSerializer},
        tags=["Notifications"],
    )
    def retrieve(self, request, *args, **kwargs):
        """获取通知详情"""
        return super().retrieve(request, *args, **kwargs)

    @extend_schema(
        summary="创建通知",
        description="""
创建一个新的通知。

权限说明：
- 只有管理员可以创建平台级别的通知
""",
        request=NotificationCreateSerializer,
        responses={201: NotificationSerializer},
        tags=["Notifications"],
    )
    def create(self, request, *args, **kwargs):
        """创建平台级别的通知"""
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        # 创建通知，不再关联具体订单
        notification = Notification.objects.create(
            recipient=serializer.validated_data.get('recipient'),
            title=serializer.validated_data.get('title'),
            content=serializer.validated_data.get('content'),
            notification_type=serializer.validated_data.get('notification_type'),
            level=serializer.validated_data.get('level')
            # 注意：不再关联订单 related_order=serializer.validated_data.get('related_order')
        )
        
        # 发送消息（微信模板消息、短信等）
        from notification_app.utils import send_notification
        
        # 通过WebSocket推送通知
        send_notification(notification)
        
        # 根据通知类型和用户偏好发送不同类型的消息
        if notification.recipient and notification.notification_type:
            # 检查用户是否订阅了微信消息
            wechat_subscriptions = notification.recipient.wechat_subscriptions.filter(
                is_active=True
            )
            
            # 发送微信模板消息
            if wechat_subscriptions.exists():
                from notification_app.utils import send_wechat_template_message
                for subscription in wechat_subscriptions:
                    # 准备模板数据
                    template_data = {
                        "first": {"value": notification.title, "color": "#173177"},
                        "keyword1": {"value": notification.content, "color": "#173177"},
                        "keyword2": {"value": notification.created_at.strftime("%Y-%m-%d %H:%M:%S"), "color": "#173177"},
                        "remark": {"value": "点击查看详情", "color": "#173177"}
                    }
                    
                    # 发送微信模板消息
                    send_wechat_template_message(
                        openid=subscription.openid,
                        template_id=subscription.template_id,
                        data=template_data,
                        url=f"https://example.com/notifications/{notification.id}"
                    )
            
            # 检查是否需要发送短信
            if notification.recipient.phone:
                from notification_app.utils import send_sms
                # 发送短信通知
                send_sms(
                    phone=notification.recipient.phone,
                    content=f"{notification.title}: {notification.content}"
                )
        
        return Response(
            NotificationSerializer(notification).data,
            status=status.HTTP_201_CREATED
        )

    @extend_schema(
        summary="获取通知列表",
        description="""
获取当前用户的通知列表。

权限说明：
- 只有通过认证的用户可以访问此接口
- 用户只能获取自己的通知

业务逻辑：
- 支持按通知类型、是否已读等条件筛选
""",
        parameters=[
            OpenApiParameter(
                name='is_read',
                type=OpenApiTypes.BOOL,
                location=OpenApiParameter.QUERY,
                description='是否已读筛选',
                required=False
            ),
            OpenApiParameter(
                name='notification_type',
                type=OpenApiTypes.STR,
                location=OpenApiParameter.QUERY,
                description='通知类型筛选，可选值: order(订单通知), payment(支付通知), system(系统通知), message(消息通知)',
                required=False
            ),
        ],
        responses={200: NotificationListSerializer(many=True)},
        tags=["Notifications"],
    )
    def list(self, request, *args, **kwargs):
        """获取通知列表"""
        return super().list(request, *args, **kwargs)

    @extend_schema(
        summary="标记通知为已读",
        description="""
标记通知为已读。
        
通过参数控制标记单个或所有通知：
- all=false或不提供: 标记指定ID的通知为已读
- all=true: 标记所有未读通知为已读

权限说明：
- 只有通过认证的用户可以访问此接口
- 用户只能标记自己的通知为已读
""",
        request={
            'application/json': {
                'type': 'object',
                'properties': {
                    'all': {
                        'type': 'boolean',
                        'description': '是否标记所有通知',
                        'default': False
                    },
                    'notification_id': {
                        'type': 'integer',
                        'description': '当all=false时，指定要标记的通知ID'
                    }
                }
            }
        },
        responses={
            200: NotificationSerializer,
            204: OpenApiTypes.OBJECT,
        },
        tags=["Notifications"],
    )
    @action(detail=False, methods=['post'])
    def mark_as_read(self, request):
        """标记通知为已读
        
        通过参数控制标记单个或所有通知：
        - 默认或all=false: 标记指定ID的通知为已读
        - all=true: 标记所有未读通知为已读
        
        参数：
        - all: 是否标记所有通知 (默认: false)
        - notification_id: 当all=false时，指定要标记的通知ID
        """
        # 检查是否标记所有通知
        mark_all = request.data.get('all', False)
        
        if mark_all:
            # 标记所有未读通知为已读
            queryset = self.get_queryset().filter(recipient=request.user, is_read=False)
            updated_count = queryset.update(
                is_read=True,
                read_at=timezone.now()
            )
            return Response({'message': f'成功标记{updated_count}条通知为已读'})
        else:
            # 标记单个通知为已读
            notification_id = request.data.get('notification_id')
            if not notification_id:
                return Response(
                    {'error': '缺少notification_id参数'},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            try:
                notification = self.get_queryset().get(id=notification_id)
            except Notification.DoesNotExist:
                return Response(
                    {'error': '通知不存在'},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # 检查当前用户是否是通知的接收者
            if notification.recipient != request.user:
                return Response(
                    {'error': '只能标记自己的通知为已读'},
                    status=status.HTTP_403_FORBIDDEN
                )
            
            if not notification.is_read:
                notification.is_read = True
                notification.read_at = timezone.now()
                notification.save()
            
            return Response(NotificationSerializer(notification).data)

    @extend_schema(
        summary="取消/删除通知",
        description="""
取消/删除指定的通知。
        
权限说明：
- 只有通过认证的用户可以访问此接口
- 用户只能删除自己的通知
""",
        responses={
            200: OpenApiTypes.OBJECT,
            403: OpenApiTypes.OBJECT,
            404: OpenApiTypes.OBJECT
        },
        tags=["Notifications"],
    )
    @action(detail=True, methods=['post'])
    def cancel(self, request, pk=None):
        """取消/删除通知"""
        notification = self.get_object()
        
        # 删除通知
        notification.delete()
        
        return Response(
            {'message': '通知删除成功'},
            status=status.HTTP_200_OK
        )


class NotificationTemplateViewSet(viewsets.ModelViewSet):
    """通知模板视图集"""
    
    queryset = NotificationTemplate.objects.all()
    serializer_class = NotificationTemplateSerializer
    permission_classes = [IsAuthenticated]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter]
    filterset_fields = ['notification_type', 'is_active']
    search_fields = ['code', 'title_template', 'content_template']


class WechatSubscriptionViewSet(viewsets.ModelViewSet):
    """微信订阅消息视图集"""
    
    queryset = WechatSubscription.objects.all()
    serializer_class = WechatSubscriptionSerializer
    permission_classes = [IsAuthenticated]
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['is_active']
    
    def get_serializer_class(self):
        """根据操作选择序列化器"""
        if self.action == 'create':
            return WechatSubscriptionCreateSerializer
        return self.serializer_class
    
    def get_queryset(self):
        """获取查询集"""
        queryset = super().get_queryset()
        
        # 只返回当前用户的订阅
        return queryset.filter(user=self.request.user)
    
    def create(self, request, *args, **kwargs):
        """创建微信订阅"""
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        # 创建订阅
        subscription = WechatSubscription.objects.create(
            user=request.user,
            template_id=serializer.validated_data.get('template_id'),
            subscription_id=serializer.validated_data.get('subscription_id'),
            expires_at=serializer.validated_data.get('expires_at')
        )
        
        return Response(
            WechatSubscriptionSerializer(subscription).data,
            status=status.HTTP_201_CREATED
        )


class MessageRecordViewSet(viewsets.ReadOnlyModelViewSet):
    """消息发送记录视图集"""
    
    queryset = MessageRecord.objects.all()
    serializer_class = MessageRecordSerializer
    permission_classes = [IsAuthenticated]
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    filterset_fields = ['message_type', 'status']
    ordering_fields = ['created_at']
    ordering = ['-created_at']
    
    def get_queryset(self):
        """获取查询集"""
        queryset = super().get_queryset()
        
        # 检查是否只获取当前用户相关的消息记录
        personal_only = self.request.query_params.get('personal_only', 'true').lower() == 'true'
        
        if personal_only:
            # 只返回与当前用户相关的消息记录
            return queryset.filter(
                Q(notification__recipient=self.request.user) |
                Q(recipient_id=self.request.user.id)
            )
        else:
            # 返回所有消息记录（需要管理员权限）
            return queryset